/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package examples;

import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.win32.W32APIOptions;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.WinDef.DWORD;
import com.sun.jna.platform.win32.Tlhelp32;
import com.sun.jna.platform.win32.WinNT;

//Imports for MyKernel32
import com.sun.jna.win32.StdCallLibrary;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.Pointer;
import com.sun.jna.Memory;
import java.util.ArrayList;
import java.util.List;
import pwned.objects.Target;

public class MyProcessReaderExample
{
    private static final boolean DEBUG = false;
    static Kernel32 kernel32 = (Kernel32)Native.loadLibrary(Kernel32.class, W32APIOptions.UNICODE_OPTIONS);
    static MyKernel32 myKernel32 = (MyKernel32)Native.loadLibrary("kernel32", MyKernel32.class);
    static Ud07 udm = (Ud07)Native.loadLibrary("D:\\Coolstory\\ml07", Ud07.class);
    static String usage = "Usage: java MyProcessReaderExample &#91processName&#93 &#91readSize&#93 &#91readAddress&#93 &#91readOffset&#93" + System.getProperty("line.separator") + "processName example: firefox.exe" + System.getProperty("line.separator") + "readSize (in bytes) example : 4" + System.getProperty("line.separator") + "readAddress (hexadecimal) example : 00010000" + System.getProperty("line.separator") + "readOffset (decimal) example : 0";
    
    interface MyKernel32 extends StdCallLibrary
    {
        // Make a homemade ReadProcessMemory (not implemented in 3.5.1 yet)
        boolean WriteProcessMemory(Pointer p, int address, Pointer buffer, int size, IntByReference written);
        boolean ReadProcessMemory(Pointer hProcess, int inBaseAddress, Pointer outputBuffer, int nSize, IntByReference outNumberOfBytesRead);
        Pointer OpenProcess(int desired, boolean inherit, int pid);
        int GetLastError();
    }
    
    interface Ud07 extends Library
    {
        // Make a homemade ReadProcessMemory (not implemented in 3.5.1 yet)
        void new_scan(int pid, int valX, int valY, int valZ, int distXY, int distZ, int[] allX);
    }
    
    public static void main(String[] args)
    {
        MyProcessReaderExample my = new MyProcessReaderExample();
        my.myExample();
        System.out.println("success test 1");
    }
    
    static List<Long> FindProcessId(String processName)
    {
        // This Reference will contain the processInfo that will be parsed to recover the ProcessId
        Tlhelp32.PROCESSENTRY32.ByReference processInfo = new Tlhelp32.PROCESSENTRY32.ByReference();
        List<Long> pids = new ArrayList<Long>();
        // This Handle allows us to parse the process map
        WinNT.HANDLE processesSnapshot = kernel32.CreateToolhelp32Snapshot(Tlhelp32.TH32CS_SNAPPROCESS, new DWORD(0L));
        if(processesSnapshot == kernel32.INVALID_HANDLE_VALUE)
        {
            if(DEBUG) System.err.println("INVALID_HANDLE_VALUE");
            return null;
        }
        
        try{// This will parse all the processes to find the process id corresponding to the process name
            kernel32.Process32First(processesSnapshot, processInfo);
            if(processName.equals(Native.toString(processInfo.szExeFile)))
            {
                if(DEBUG) System.out.println("Process " + processName + " found : " + processInfo.th32ProcessID.longValue());
                pids.add(processInfo.th32ProcessID.longValue());
                return pids;
            }
            
            while(kernel32.Process32Next(processesSnapshot, processInfo))
            {
                if(processName.equals(Native.toString(processInfo.szExeFile)))
                {
                    if(DEBUG) System.out.println("Process " + processName + " found : " + processInfo.th32ProcessID.longValue());
                    pids.add(processInfo.th32ProcessID.longValue());
                }
            }
            
            return pids;
        }
        finally
        {
            kernel32.CloseHandle(processesSnapshot);
        }
        
    }
    
    private void myExample(){
        
        int rights = 0x0010 + 0x0020 + 0x0008;
        int m = 65536;
        
        int DistXYParam = 320;
        int DistZParam = 250;
        int[] dllStruct = new int[10000];
        System.out.println(dllStruct.toString());
        
        int baseDLL = 0x10000000;
        
        String processName = "dfuw.exe";
        List<Long> processId = FindProcessId(processName); //6000;//
        
        int readSize = 4;
        //int readAddress = 0x012F0C38;
        int readOffset = 0;
        
        Memory output = new Memory(readSize);
        
        int pid = processId.get(1).intValue();
        
        Pointer openedProcess = myKernel32.OpenProcess(rights, true, pid);
        
        int value = 0;
        
        boolean success;
        success = myKernel32.ReadProcessMemory(openedProcess, baseDLL + 0x012F0C38, output, readSize, new IntByReference(0));
        
        if(!success)
            {
                int error = myKernel32.GetLastError();
                switch(error)
                {
                    default:
                        System.err.println("Failed to read the process : " + error);
                        break;
                    case 0x12B:
                        System.err.println("Failed to read the specified address");
                        break;
                }
                System.exit(1);
            }
        
        if( success ){
            value = output.getInt(readOffset);
        }
        System.out.println("value: "+value);
        
        success = myKernel32.ReadProcessMemory(openedProcess, value + 0x168, output, readSize, new IntByReference(0));
        if( success ){
            value = output.getInt(readOffset);
        }
        System.out.println("value: "+value);
        
        success = myKernel32.ReadProcessMemory(openedProcess, value + 0x58, output, readSize, new IntByReference(0));
        if( success ){
            value = output.getInt(readOffset);
        }
        System.out.println("value: "+value);
        
        success = myKernel32.ReadProcessMemory(openedProcess, value + 0x50, output, readSize, new IntByReference(0));
        if( success ){
            value = output.getInt(readOffset);
        }
        System.out.println("value: "+value);
        
        success = myKernel32.ReadProcessMemory(openedProcess, value + 0x10, output, readSize, new IntByReference(0));
        if( success ){
            value = output.getInt(readOffset);
        }
        System.out.println("value: "+value);
        
        success = myKernel32.ReadProcessMemory(openedProcess, value + 0x1c4, output, readSize, new IntByReference(0));
        if( success ){
            value = output.getInt(readOffset);
        }
        System.out.println("value: "+value);
        
        success = myKernel32.ReadProcessMemory(openedProcess, value + 0xc, output, readSize, new IntByReference(0));
        if( success ){
            value = output.getInt(readOffset);
        }
        System.out.println("value: "+value);
        
        success = myKernel32.ReadProcessMemory(openedProcess, value + 0x28, output, readSize, new IntByReference(0));
        if( success ){
            value = output.getInt(readOffset);
        }
        System.out.println("value: "+value);
        
        success = myKernel32.ReadProcessMemory(openedProcess, value + 0x0, output, readSize, new IntByReference(0));
        if( success ){
            value = output.getInt(readOffset);
        }
        System.out.println("value: "+value);
        
        success = myKernel32.ReadProcessMemory(openedProcess, value + 0x8, output, readSize, new IntByReference(0));
        if( success ){
            value = output.getInt(readOffset);
        }
        System.out.println("value: "+value);
        
        success = myKernel32.ReadProcessMemory(openedProcess, value + 0xc, output, readSize, new IntByReference(0));
        if( success ){
            value = output.getInt(readOffset);
        }
        System.out.println("value final!!!: "+value);
        
        int x = 0;
        success = myKernel32.ReadProcessMemory(openedProcess, value + 0x14, output, readSize, new IntByReference(0));
        if( success ){
            x = output.getInt(readOffset);
        }
        System.out.println("x: "+x);
        
        int y = 0;
        success = myKernel32.ReadProcessMemory(openedProcess, value + 0x14 + 0x8, output, readSize, new IntByReference(0));
        if( success ){
            y = output.getInt(readOffset);
        }
        System.out.println("y: "+y);
        
        int z = 0;
        success = myKernel32.ReadProcessMemory(openedProcess, value + 0x14 + 0x4, output, readSize, new IntByReference(0));
        if( success ){
            z = output.getInt(readOffset);
        }
        z = (int) (z + (0.5 * m));
        System.out.println("z: "+z);
        
//        $x1 =  _MemoryRead($baseDLL + Dec("012F0C38"), $hMemory)
//        ;$x2 =  _MemoryRead($x1+Dec("4"), $hMemory)
//        $x3 =  _MemoryRead($x1+Dec("168"), $hMemory)
//        $x4 =  _MemoryRead($x3+Dec("58"), $hMemory)
//        $x5 =  _MemoryRead($x4+Dec("50"), $hMemory)
//        $x6 =  _MemoryRead($x5+Dec("10"), $hMemory)
//        $x7 =  _MemoryRead($x6+Dec("1c4"), $hMemory)
//        $x8 =  _MemoryRead($x7+Dec("c"), $hMemory)
//        $x9 =  _MemoryRead($x8+Dec("28"), $hMemory)
//        $x10 =  _MemoryRead($x9+Dec("0"), $hMemory)
//        $x11 =  _MemoryRead($x10+Dec("8"), $hMemory)
//        $x12 =  _MemoryRead($x11+Dec("c"), $hMemory)
//
//        $X = _UnsToS(_MemoryRead($x12+Dec("14"), $hMemory))
//        $Y = _UnsToS(_MemoryRead($x12+Dec("14")+Dec("8"), $hMemory))
//        $Z = _UnsToS(_MemoryRead($x12+Dec("14")+Dec("4"), $hMemory))
        
        int ud = 0;
        
        success = myKernel32.ReadProcessMemory(openedProcess, baseDLL + 0x01253A0C, output, readSize, new IntByReference(0));
        if( success ){
            ud = output.getInt(readOffset);
        }
        System.out.println("ud1: "+ud);
        
        success = myKernel32.ReadProcessMemory(openedProcess, ud + 0xd0, output, readSize, new IntByReference(0));
        if( success ){
            ud = output.getInt(readOffset);
        }
        System.out.println("ud2: "+ud);
        
        success = myKernel32.ReadProcessMemory(openedProcess, ud + 0x16c, output, readSize, new IntByReference(0));
        if( success ){
            ud = output.getInt(readOffset);
        }
        System.out.println("ud3: "+ud);
        
        success = myKernel32.ReadProcessMemory(openedProcess, ud + 0x44, output, readSize, new IntByReference(0));
        if( success ){
            ud = output.getInt(readOffset);
        }
        System.out.println("ud4: "+ud);
        
        success = myKernel32.ReadProcessMemory(openedProcess, ud + 0x8, output, readSize, new IntByReference(0));
        if( success ){
            ud = output.getInt(readOffset);
        }
        System.out.println("ud5: "+ud);
        
        float ud1 = 0.0f;
        success = myKernel32.ReadProcessMemory(openedProcess, ud + 0x3f4, output, readSize, new IntByReference(0));
        if( success ){
            ud1 = output.getFloat(readOffset);
        }
        System.out.println("!!ud1!!: "+ud1);
        
        float ns = 0.0f;
        success = myKernel32.ReadProcessMemory(openedProcess, ud + 0x3f4 + 0x4, output, readSize, new IntByReference(0));
        if( success ){
            ns = output.getFloat(readOffset);
        }
        System.out.println("!!ns!!: "+ns);
        
        float we = 0.0f;
        success = myKernel32.ReadProcessMemory(openedProcess, ud + 0x3f4 - 0x4, output, readSize, new IntByReference(0));
        if( success ){
            we = output.getFloat(readOffset);
        }
        System.out.println("!!we!!: "+we);
        
//        $ud1 =  _MemoryRead($baseDLL + Dec("01253A0C"), $hMemory)
//        $ud2 =  _MemoryRead($ud1+Dec("d0"), $hMemory)
//        $ud3 =  _MemoryRead($ud2+Dec("16c"), $hMemory)
//        $ud4 =  _MemoryRead($ud3+Dec("44"), $hMemory)
//        $ud5 =  _MemoryRead($ud4+Dec("8"), $hMemory)
//
//        $ud =  _MemoryRead($ud5 + Dec("3f4"), $hMemory, 'float')
//        $ns = _MemoryRead($ud5 + Dec("3f4")+Dec("4"), $hMemory, 'float')
//        $we = _MemoryRead($ud5 + Dec("3f4")-Dec("4"), $hMemory, 'float')
        
        udm.new_scan(pid, x, y, z, DistXYParam, DistZParam, dllStruct);
       
        System.out.println("dllStruct: "+dllStruct);
        
        List<Target> targets = new ArrayList<>();
        
        List<Integer> adresses = getDllValues(dllStruct);
        for( Integer adress : adresses ){
            
            float ix1976 = 0.0f;
            success = myKernel32.ReadProcessMemory(openedProcess, adress + 1976, output, readSize, new IntByReference(0));
            if( success ){
                ix1976 = output.getFloat(readOffset);
            }
            System.out.println("ix1976: "+ix1976);
            
            float ix1980 = 0.0f;
            success = myKernel32.ReadProcessMemory(openedProcess, adress + 1980, output, readSize, new IntByReference(0));
            if( success ){
                ix1980 = output.getFloat(readOffset);
            }
            System.out.println("ix1980: "+ix1980);
            
            float ix1984 = 0.0f;
            success = myKernel32.ReadProcessMemory(openedProcess, adress + 1984, output, readSize, new IntByReference(0));
            if( success ){
                ix1984 = output.getFloat(readOffset);
            }
            System.out.println("ix1984: "+ix1984);
            
            float sumQ = ix1976 * ix1976 + ix1984 * ix1984 + ix1980 * ix1980;
            
            if( sumQ > 0.97 && sumQ < 1.03 && ix1976 > 0 && ix1976 < 1 && ix1984 > 0 && ix1984 < 1){
                
                long ix1960 = 0;
                success = myKernel32.ReadProcessMemory(openedProcess, adress + 1960, output, 8, new IntByReference(0));
                if( success ){
                    ix1960 = unsToS( output.getInt(readOffset) );
                }
                System.out.println("ix1960: "+ix1960); 
                
                long iy1960 = 0;
                success = myKernel32.ReadProcessMemory(openedProcess, adress + 8 + 1960, output, 8, new IntByReference(0));
                if( success ){
                    iy1960 = unsToS( output.getInt(readOffset) );
                }
                System.out.println("iy1960: "+iy1960);
                
                long iz1960 = 0;
                success = myKernel32.ReadProcessMemory(openedProcess, adress + 4 + 1960, output, 8, new IntByReference(0));
                if( success ){
                    iz1960 = unsToS( output.getInt(readOffset) );
                }
                System.out.println("iz1960: "+iz1960);
                
                
//               $ix1960 = _UnsToS(_MemoryRead($i + 1960, $hMemory))
//		 $iy1960 = _UnsToS(_MemoryRead($i + 8 + 1960, $hMemory))
//		 $iz1960 = _UnsToS(_MemoryRead($i + 4 + 1960, $hMemory))
                
                
                int dx = (int) (x - ix1960);
                int aDX = Math.abs(dx);
                int dy = (int) (y - iy1960);
                int aDY = Math.abs(dy);
                
                int dist = (int) Math.sqrt( (aDX * aDX) + (aDY * aDY) );
                
                Target target = new Target();
                target.setX( adress + 1960 );
                target.setY( adress + 1960 + 8 );
                target.setZ( adress + 1960 + 4 );
                target.setDistance(dist);
                target.setNewTarget(true);
                target.setB2(false);
                target.setB3(false);
                
                targets.add( target );
                
//                $Array[UBound($Array) - 1][0] = Hex($i + 1960)
//			$Array[UBound($Array) - 1][1] = Hex($i + 1960 + 8)
//			$Array[UBound($Array) - 1][2] = Hex($i + 1960 + 4)
//			$Array[UBound($Array) - 1][3] = $dist 
//			$Array[UBound($Array) - 1][4] = True 
//			$Array[UBound($Array) - 1][5] = False 
//			$Array[UBound($Array) - 1][6] = False 
                
                
//               $dx = $x - $ix1960
//		 $aDX = Abs($dx)
//		 $dy = $y - $iy1960
//		 $aDY = Abs($dy)
//		 $dist = Int(Sqrt($adx * $adx + $ady * $ady))
                
            }
            
//            $ix1976 = Abs(_MemoryRead($i + 1976, $hMemory, 'float'))
//            $ix1980 = Abs(_MemoryRead($i + 1980, $hMemory, 'float'))
//            $ix1984 = Abs(_MemoryRead($i + 1984, $hMemory, 'float'))
        }
        System.out.println("targets: "+targets.size());
    }
    
    private List getDllValues( final int[] dllStructur ){
        final List<Integer> values = new ArrayList<>();
        for( int i = 1 ; i < dllStructur.length ; i++){
            int val = dllStructur[i];
            if( val > 0 ){
                values.add(val);
            }
        }
        return values;
    }
    
    private Integer getCount( final int[] dllStructur ){
        return dllStructur[0];
    }
    
    private Long unsToS( long uns ){
    
        if( uns > 2147483648l ){
            return uns - 4294967296l;
        }else{
            return uns;
        }
        
    }
   
    
    private void example(){
        //        if(args.length < 4)
//        {
//            System.err.println(usage);
//            System.exit(1);
//        }
        
        
        int baseDLL = 0x10000000;
        int x1;
        
        String processName = "df.exe";
        int readSize = 6;
        int readAddress = 0x012F0C38; //000100E8
        int readOffset = 0;
//        try{
//            processName = args[0];//Defines the name of the process to search for
//            readSize = Integer.parseInt(args[1], 10);//Defines the size of the value to read
//            readAddress = Integer.parseInt(args[2], 16);//Defines the address of the value to read (hexadecimal)
//            readOffset = Integer.parseInt(args[3], 10);//Defines the offset of the value to read
//        }
//        catch(NumberFormatException e)
//        {
//            System.err.println(usage);
//            System.exit(1);
//        }
        
        
        
        List<Long> processId = FindProcessId(processName);//Searchs for a process id from its name
        if(processId == null)//The process was not found
        {
            System.err.println("The searched process was not found : " + processName);
            System.exit(1);
        }
        System.out.println(processName + " id : " + processId);//Shows us the process id
        
        int pid2 = processId.get(0).intValue();
//        ud.new_scan(pid2,0,0,0,0,0,0);
        
        /*
        WinNT.HANDLE openedProcess = kernel32.OpenProcess(kernel32.READ_CONTROL, false, (int)processId);//Open the process with access right (http://msdn.microsoft.com/en-us/library/windows/desktop/ms684880%28v=vs.85%29.aspx)
        if(openedProcess == null)//Could not open the process
        {
            System.err.println("Could not open the process : " + kernel32.GetLastError());
            System.exit(1);
        }
        */
        
        int rights = 0x0010 + 0x0020 + 0x0008;//kernel32.PROCESS_VM_READ (0x0010), kernel32.PROCESS_VM_WRITE (0x0020), kernel32.VM_OPERATION (0x0008)
        Pointer openedProcess = myKernel32.OpenProcess(rights, true, pid2);//Open the process under read access rights
        if(openedProcess == null)//Could not open the process
        {
            System.err.println("Could not open the process : " + myKernel32.GetLastError());
            System.exit(1);
        }
        
        int readValue = 0;
        {
            Memory output = new Memory(readSize);
            if(!myKernel32.ReadProcessMemory(openedProcess, readAddress, output, readSize, new IntByReference(0)))
            {
                int error = myKernel32.GetLastError();
                switch(error)
                {
                    default:
                        System.err.println("Failed to read the process : " + error);
                        break;
                    case 0x12B:
                        System.err.println("Failed to read the specified address");
                        break;
                }
                System.exit(1);
            }
            readValue = output.getInt(readOffset);
            byte[] valbyte = new byte[6];
            
            System.out.println(readValue + " has been read at 0x"  + "+" + readOffset + " on " + readSize + "bytes.");
        }
        
        {// Increase the read value by one
            IntByReference written = new IntByReference(0);
            Memory toWrite = new Memory(readSize);
            toWrite.setInt(readOffset, readValue+1);//This should change if the readSize is different than 4
            if(!myKernel32.WriteProcessMemory(openedProcess, readAddress, toWrite, 1, written))
            {
                int error = myKernel32.GetLastError();
                switch(error)
                {
                    default:
                        System.err.println("Failed to write in the process : " + error);
                        break;
                }
                System.exit(1);
            }
            System.out.println("Wrote " + written.getValue() + " times.");
        }
        
        {// Read again the value
            Memory output = new Memory(readSize);
            if(!myKernel32.ReadProcessMemory(openedProcess, readAddress, output, readSize, new IntByReference(0)))
            {
                int error = myKernel32.GetLastError();
                switch(error)
                {
                    default:
                        System.err.println("Failed to read the process : " + error);
                        break;
                    case 0x12B:
                        System.err.println("Failed to read the specified address");
                        break;
                }
                System.exit(1);
            }
            readValue = output.getInt(readOffset);
            System.out.println(readValue + " has been read at 0x" + "+" + readOffset + " on " + readSize + "bytes.");
        }
        
        {// Restore the read value to its original state
            IntByReference written = new IntByReference(0);
            Memory toWrite = new Memory(readSize);
            toWrite.setInt(readOffset, readValue-1);//This should change if the readSize is different than 4
            if(!myKernel32.WriteProcessMemory(openedProcess, readAddress, toWrite, 1, written))
            {
                int error = myKernel32.GetLastError();
                switch(error)
                {
                    default:
                        System.err.println("Failed to write in the process : " + error);
                        break;
                }
                System.exit(1);
            }
            System.out.println("Wrote " + written.getValue() + " times.");
        }
        
        {// Read again the value
            Memory output = new Memory(readSize);
            if(!myKernel32.ReadProcessMemory(openedProcess, readAddress, output, readSize, new IntByReference(0)))
            {
                int error = myKernel32.GetLastError();
                switch(error)
                {
                    default:
                        System.err.println("Failed to read the process : " + error);
                        break;
                    case 0x12B:
                        System.err.println("Failed to read the specified address");
                        break;
                }
                System.exit(1);
            }
            readValue = output.getInt(readOffset);
            System.out.println(readValue + " has been read at 0x" + "+" + readOffset + " on " + readSize + "bytes.");
        }
    }
}